package main

import (
	"certificate-manager/pkg/constant"
	"certificate-manager/pkg/log"
	"certificate-manager/pkg/setting"
	"certificate-manager/pkg/utils"
	"certificate-manager/routers"
	acmee "certificate-manager/thirdparty/acmee"
	"certificate-manager/thirdparty/feishu"
	"certificate-manager/thirdparty/redisc"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-redsync/redsync/v4"
	"github.com/go-redsync/redsync/v4/redis/goredis/v8"
	"github.com/robfig/cron"
	"go.uber.org/zap"
	"net/http"
	"os"
	"time"
)

func initCertificateCheck() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("panic: %v %v %v\n", utils.CurrentTime(), utils.RunFuncName(), err)
		}
	}()

	//1、初始化 redis 客户端
	rdb, err := redisc.GetRedisClientInstance()
	if err != nil {
		log.Logger.Error("【Main Init】failed to create redis client.", zap.Any("err", err))
		feishu.SendAlertMsg(fmt.Sprintf(feishu.AtMsg, os.Getenv("NAMESPACE"), utils.CurrentTime(), utils.RunFuncName(), err))
		return
	}

	log.Logger.Info("【Main Init】get redis client success.")

	//2、抢占分布式锁，未抢占到锁的进程直接跳过
	rs := redsync.New(goredis.NewPool(rdb.Client))
	mutex := rs.NewMutex(constant.LockKey, redsync.WithExpiry(time.Duration(constant.RedisLockTimeSeconds)*time.Second))
	if err := mutex.TryLock(); err != nil {
		log.Logger.Info("【Main Init】can not obtain redis lock.")
		return
	}

	//3、初始化 acmez client
	client, err := acmee.GetAcmeClientInstance()
	if err != nil {
		log.Logger.Error("【Main Init】failed to create ACMEz client", zap.Any("err", err))
		feishu.SendAlertMsg(fmt.Sprintf(feishu.AtMsg, os.Getenv("NAMESPACE"), utils.CurrentTime(), utils.RunFuncName(), err))
		return
	}

	log.Logger.Info("【Main Init】successfully get acmez client")

	//4、初始化 Let's encrypt Account
	account, err := acmee.GetAcmeAccountInstance(rdb)
	if err != nil || account == nil {
		log.Logger.Error("【Main Init】failed to get let's encrypt account from redis", zap.Any("err", err))
		feishu.SendAlertMsg(fmt.Sprintf(feishu.AtMsg, os.Getenv("NAMESPACE"), utils.CurrentTime(), utils.RunFuncName(), err))
		return
	}

	log.Logger.Info("【Main Init】get let's encrypt account success")

	//5、初始化的时候检查证书是否创建
	err = acmee.CheckSSLCertificateExpirationAndIssuer(rdb, account, client)
	if err != nil {
		log.Logger.Sugar().Errorf("%v %v", utils.RunFuncName(), err)
	}

	//6、释放redis锁
	defer func() {
		if ok, err := mutex.Unlock(); !ok {
			log.Logger.Error("【Main Init】failed to unlock redis lock.", zap.Any("err", err))
			return
		}
	}()
}

func startIssueJob() {
	c := cron.New()

	//5分钟执行一次
	//err := c.AddFunc("0 */5 * * * *", func() {
	err := c.AddFunc("*/5 * * * *", func() {
		log.Logger.Sugar().Infof("start issue job: %v", time.Now().Local())

		//1、初始化 redis 客户端
		rdb, err := redisc.GetRedisClientInstance()
		if err != nil {
			log.Logger.Error("【Start Corn】failed to create redis client.", zap.Any("err", err))
			feishu.SendAlertMsg(fmt.Sprintf(feishu.AtMsg, os.Getenv("NAMESPACE"), utils.CurrentTime(), utils.RunFuncName(), err))
			return
		}

		//2、初始化acmeClient
		client, err := acmee.GetAcmeClientInstance()
		if err != nil {
			log.Logger.Error("【Start Corn】failed to create ACMEz client", zap.Any("err", err))
			feishu.SendAlertMsg(fmt.Sprintf(feishu.AtMsg, os.Getenv("NAMESPACE"), utils.CurrentTime(), utils.RunFuncName(), err))
			return
		}

		//3、初始化acmeAccount
		account, err := acmee.GetAcmeAccountInstance(rdb)
		if err != nil || account == nil {
			log.Logger.Error("【Start Corn】failed to get let's encrypt account from redis", zap.Any("err", err))
			feishu.SendAlertMsg(fmt.Sprintf(feishu.AtMsg, os.Getenv("NAMESPACE"), utils.CurrentTime(), utils.RunFuncName(), err))
			return
		}

		//4、执行定时任务
		err = acmee.IssueJob(rdb, client, account)
		if err != nil {
			log.Logger.Error("【Start Issue Job】job execution failure.", zap.Any("err", err))
			feishu.SendAlertMsg(fmt.Sprintf(feishu.AtMsg, os.Getenv("NAMESPACE"), utils.CurrentTime(), utils.RunFuncName(), err))
			return
		}
	})

	if err != nil {
		log.Logger.Error("【Start Issue Job】Start Issue Job Failed.", zap.Any("err", err))
		feishu.SendAlertMsg(fmt.Sprintf(feishu.AtMsg, os.Getenv("NAMESPACE"), utils.CurrentTime(), utils.RunFuncName(), err))
		return
	}
	c.Start()
}

func init() {
	log.Setup()
	setting.Setup()
	acmee.Setup()
	//初始化证书检查
	initCertificateCheck()
}

func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("panic: %v %v %v\n", utils.CurrentTime(), utils.RunFuncName(), err)
		}
	}()

	//1、启动定时任务
	startIssueJob()

	//2、启动webserver
	gin.SetMode(setting.ServerSetting.RunMode)

	routersInit := routers.InitRouter()
	readTimeout := setting.ServerSetting.ReadTimeout
	writeTimeout := setting.ServerSetting.WriteTimeout

	endPoint := fmt.Sprintf(":%d", setting.ServerSetting.HttpPort)

	server := &http.Server{
		Addr:         endPoint,
		Handler:      routersInit,
		ReadTimeout:  readTimeout,
		WriteTimeout: writeTimeout,
	}

	log.Logger.Info("【Start Server】start http server", zap.Any("listen", endPoint))

	err := server.ListenAndServe()
	if err != nil {
		log.Logger.Error("【Start Server】start server error.", zap.Any("err", err))
	}
}
